package edu.scut.course_management.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import edu.scut.course_management.dao.CourseMapper;
import edu.scut.course_management.dao.CourseNoticeMapper;
import edu.scut.course_management.dao.CourseTypeMapper;
import edu.scut.course_management.dao.DepartmentMapper;
import edu.scut.course_management.dao.MajorMapper;
import edu.scut.course_management.dao.SectionMapper;
import edu.scut.course_management.dao.TakesMapper;
import edu.scut.course_management.dao.TeachesMapper;
import edu.scut.course_management.dto.AddCourseDTO;
import edu.scut.course_management.dto.CourseListInfo;
import edu.scut.course_management.dto.GetConcreteCourse;
import edu.scut.course_management.dto.GetCourseListDTO;
import edu.scut.course_management.dto.GetCourseListOfS;
import edu.scut.course_management.dto.GetCourseListOfT;
import edu.scut.course_management.dto.GetListOfStudentsDTO;
import edu.scut.course_management.dto.GetNoticeListDTO;
import edu.scut.course_management.dto.SearchCourseListOfM;
import edu.scut.course_management.dto.TimePlace;
import edu.scut.course_management.exception.CustomException;
import edu.scut.course_management.po.Course;
import edu.scut.course_management.po.Section;
import edu.scut.course_management.po.Sections;
import edu.scut.course_management.po.Takes;
import edu.scut.course_management.po.Teaches;
import edu.scut.course_management.result.ResultCode;

@Service
public class CourseInfoService {
    @Autowired
    TakesMapper takesMapper;

    @Autowired
    DepartmentMapper departmentMapper;

    @Autowired
    MajorMapper majorMapper;

    @Autowired
    TeachesMapper teachesMapper;

    @Autowired
    SectionMapper sectionMapper;

    @Autowired
    CourseMapper courseMapper;

    @Autowired
    CourseNoticeMapper courseNoticeMapper;

    @Autowired
    CourseTypeMapper courseTypeMapper;
    //返回课程学生信息列表
    public List<GetListOfStudentsDTO> getStudentsList(List<Section> sections) throws CustomException{
        Section section = sections.get(0);
        List<GetListOfStudentsDTO> list = takesMapper.findByStudentId(section);
        //逻辑判断，0 - 男； 1 - 女
        if(list.isEmpty()){
            throw new CustomException(ResultCode.PARAM_IS_BLANK);
        }
        for(GetListOfStudentsDTO student: list){
            if(student.getMale() == "0"){
                student.setMale("男");
            }
            else{
                student.setMale("女");
            }
        }
        return list;
    }

    // 新增、修改课程信息
    public void updateCourse(AddCourseDTO addCourseDTO) throws CustomException{
        // 判断修改的课程（course表中）是否存在
        Course course = courseMapper.findByattriExceptId(addCourseDTO);
        Integer courseId;
        if (course == null) {
            // course不存在，属于从未开设过的课程
            try{
                Integer courseTypeId = courseTypeMapper.findCourseTypeId(addCourseDTO.getCourseTypeName());
                Integer departmentId = departmentMapper.findDepartmentId(addCourseDTO.getDepartmentName());
                courseMapper.addCourse(new Course(addCourseDTO, courseTypeId, departmentId));
                courseId = courseMapper.findCourseId(addCourseDTO);
            }catch(DataAccessException e){
                throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
            }
        }
        else{
            courseId = course.getCourseId();
        }
        // course存在，则不用添加

        //前端传过来的原始sections
        List<Sections> sections_init = addCourseDTO.getSections();
        List<String> studentIdList = addCourseDTO.getStudentId();

        //存储对应要添加的section，teaches和takes
        List<Section> sections = new ArrayList<>();
        List<Teaches> teaches = new ArrayList<>();
        List<Takes> takes = new ArrayList<>();

        Integer periodId;
        String year = addCourseDTO.getYear();
        String term = addCourseDTO.getTerm();

        //identifier获取与唯一性检验
        List<String> identifierList = teachesMapper.findAllIdentifier();
        String identifier = "0";
        do{
            Date date = new Date();
            int seed = date.getMinutes() + date.getSeconds();
            Random random = new Random(seed);
            identifier = Integer.toString(random.nextInt(100000));
        }while(identifierList.contains(identifier));
        

        //将原始section转换成库表对应的形式（以列表形式存储）
        for(Sections a: sections_init){
            periodId = timeToPeriodId(a.getTime());
            Section s = new Section(periodId, year, term, courseId, a.getBuildingId(), a.getRoomNumber());
            sections.add(s);
            //将该section加到授课教师的teaches中
            teaches.add(new Teaches(addCourseDTO.getTeacherId(), s, identifier));
            //将该section加到每个上课学生的takes中
            for(String studentId: studentIdList){
                takes.add(new Takes(studentId, s));
            }
        }
        //添加数据库操作
        try{
            sectionMapper.addSection(sections);
            teachesMapper.addTeaches(teaches);
            takesMapper.addTakes(takes);
        }catch(DataAccessException e){
            throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
        }
    }

    //删除课程信息
    public void DeleteSections(List<Section> sections) throws CustomException{
        try{
            sectionMapper.deleteSections(sections);
        }catch(DataAccessException e){
            throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
        }
        
    }

    // 返回课程信息列表(管理员)
    public List<GetCourseListDTO> GetCourseListOfMonitor(SearchCourseListOfM searchCourseListOfM){
        //根据查询条件获取对应的教学（teaches）关系列表
        List<Teaches> listOfTeaches = teachesMapper.findTeachesToGetList(searchCourseListOfM);
        //把sections分好组
        List<Teaches> teacherList = new ArrayList<>();//存储不同课程的授课教师
        List<List<Section>> totalList = new ArrayList<>();
        String identifier = "";
        List<Section> sectionsList = new ArrayList<>();
        for(Teaches teaches: listOfTeaches){
            String id = teaches.getIdentifier();
            if(!id.equals(identifier)){
                if(identifier == ""){//当扫描的是listOfTeaches的第一个元素时
                    
                    identifier = teaches.getIdentifier();
                    teacherList.add(teaches);
                }
                else{//当检索到的课程section和前面的section不属于同一门课时
                    totalList.add(sectionsList);
                    sectionsList = new ArrayList<>();
                    teacherList.add(teaches);//将不同课程的老师授课关系teaches存起来，用于后续查询
                    identifier = teaches.getIdentifier();
                }
            }
            sectionsList.add(teaches.getSection());
        }

        totalList.add(sectionsList);//把最后一组sectionList添加到totalList中

        List<GetCourseListDTO> finalList = new ArrayList<>();//存储最终要返回的DTO对象
        if(teacherList.isEmpty()){
            return finalList;
        }
        List<CourseListInfo> courseListInfos = teachesMapper.findCourseInfoByTeachesList(teacherList);
        int i = 0;//计数器，用来计算到了列表哪个课程
        for(List<Section> sections: totalList){
            GetCourseListDTO getCourseListDTO = new GetCourseListDTO();
            getCourseListDTO.setSections(sections);
            
            getCourseListDTO.setTimePlace(TimePalcesConvert(sections));

            //CourseListInfo(在dto里)：title，courseTypeName，classHours,credits,name
            //sections[0]里面有year和term
            String year = sections.get(0).getYear();
            String term = sections.get(0).getTerm();
            getCourseListDTO.setBasicAttris(courseListInfos.get(i++), year, term);

            finalList.add(getCourseListDTO);
        }

        return finalList;
    }

    // 返回课程信息列表(教师)
    public List<GetCourseListDTO> GetCourseListOfTeacher(String teacherId){
        //根据输入的教师Id从数据库查询需要的课程信息
        List<GetCourseListOfT> interList = teachesMapper.findCourseInfoByTeacherId(teacherId);
        
        //数据处理
        List<Section> sections = new ArrayList<>();
        List<GetCourseListDTO> finalList = new ArrayList<>();//用来存储最终结果
        int i = 0;//计数器
        String identifierBefore = "";
        for(GetCourseListOfT item: interList){
            Section section = item.getTeaches().getSection();
            if(i == 0){//当为列表第一个元素时
                sections.add(section);
                identifierBefore = item.getTeaches().getIdentifier();
            }
            else{
                if(item.getTeaches().getIdentifier().equals(identifierBefore)){//当section和上一个section同属同一门课时
                    sections.add(section);

                }
                else{//当section和上一个section不属于同一门课时
                    GetCourseListDTO getCourseListDTO = new GetCourseListDTO();
                    getCourseListDTO.setIdentifier(identifierBefore);
                    getCourseListDTO.setSections(sections);
                    getCourseListDTO.setTimePlace(TimePalcesConvert(sections));
                    getCourseListDTO.setTitle(interList.get(i-1).getTitle());//设置为上一个section的课程名
                    finalList.add(getCourseListDTO);//将该课程添加到列表中
                    sections = new ArrayList<>();//重新初始化sections
                    sections.add(section);
                    identifierBefore = item.getTeaches().getIdentifier();
                }
            }
            i++;//计数器自增
        }
        GetCourseListDTO getCourseListDTO = new GetCourseListDTO();
        getCourseListDTO.setIdentifier(identifierBefore);
        getCourseListDTO.setSections(sections);
        getCourseListDTO.setTimePlace(TimePalcesConvert(sections));
        getCourseListDTO.setTitle(interList.get(i-1).getTitle());

        finalList.add(getCourseListDTO);//将该课程添加到列表中

        return finalList;
    }

    // 返回课程信息列表(学生)
    public List<GetCourseListDTO> GetCourseListOfStudent(String studentId){
        //根据输入的学生Id从数据库查询需要的课程信息
        List<GetCourseListOfS> interList = teachesMapper.findCourseInfoByStudentId(studentId);

        //数据处理
        List<Section> sections = new ArrayList<>();
        List<GetCourseListDTO> finalList = new ArrayList<>();//用来存储最终结果

        int i = 0;//计数器
        String identifierBefore = "";
        for(GetCourseListOfS item: interList){
            Section section = item.getTeaches().getSection();
            if(i == 0){//当为列表第一个元素时
                sections.add(section);
                identifierBefore = item.getTeaches().getIdentifier();
            }
            else{
                if(item.getTeaches().getIdentifier().equals(identifierBefore)){//当section和上一个section同属同一门课时
                    sections.add(section);

                }
                else{//当section和上一个section不属于同一门课时
                    GetCourseListDTO getCourseListDTO = new GetCourseListDTO();
                    getCourseListDTO.setIdentifier(identifierBefore);
                    getCourseListDTO.setSections(sections);
                    getCourseListDTO.setName(interList.get(i-1).getName());//设置为上一个section的老师姓名
                    getCourseListDTO.setTitle(interList.get(i-1).getTitle());//设置为上一个section的课程名
                    finalList.add(getCourseListDTO);//将该课程添加到列表中
                    sections = new ArrayList<>();//重新初始化sections
                    sections.add(section);
                    identifierBefore = item.getTeaches().getIdentifier();
                }
            }
            i++;//计数器自增
        }
        GetCourseListDTO getCourseListDTO = new GetCourseListDTO();
        getCourseListDTO.setIdentifier(identifierBefore);
        getCourseListDTO.setSections(sections);
        getCourseListDTO.setName(interList.get(i-1).getName());//设置为上一个section的老师姓名
        getCourseListDTO.setTitle(interList.get(i-1).getTitle());

        finalList.add(getCourseListDTO);//将该课程添加到列表中

        return finalList;

    }
    
    //返回某门课程具体信息（学生）
    public GetConcreteCourse getCourseInfoOfS(List<Section> sections){
        //关于sections是否为空的问题放在controller中检验
        //取出第一个section用于数据库查询
        Section section = sections.get(0);
        GetConcreteCourse concreteCourse = sectionMapper.findConcreteCourseOfSBySection(section);
        concreteCourse.setTimePlace(TimePalcesConvert(sections));
        return concreteCourse;
    }

    //返回某门课程具体信息（教师）
    public GetConcreteCourse getCourseInfoOfT(List<Section> sections){
        //关于sections是否为空的问题放在controller中检验
        //取出第一个section用于数据库查询
        Section section = sections.get(0);
        GetConcreteCourse concreteCourse = sectionMapper.findConcreteCourseOfTBySection(section);
        concreteCourse.setTimePlace(TimePalcesConvert(sections));
        return concreteCourse;
    }

    //返回课程通告(学生)
    public List<GetNoticeListDTO> getCourseNotice(List<Section> sections){
        //关于sections是否为空的问题放在controller中检验
        //取出第一个section用于数据库查询
        Section section = sections.get(0);
        List<GetNoticeListDTO> NoticeList = courseNoticeMapper.findNoticeBySection(section);
        return NoticeList;
    }

    //添加课程通告(教师),返回成功更新的记录条数，用于controller后续操作
    public Integer addCourseNotice(String title, String content, String time, List<Section> sections) throws CustomException{
        //数据校验
        if(isEmpty(title)){
            title ="无标题";
        }
        Integer updatesNum = new Integer("0");
        try{
            updatesNum = courseNoticeMapper.addCourseNotice(title, content, time, sections);
        }catch(DataAccessException e){
            throw new CustomException(ResultCode.DATABASE_UPDATE_FAIL);
        }
        
        return updatesNum;
    }

    //数据校验：判断输入字符串是否为空，空串或是空格串
    public static boolean isEmpty(String ...strings){
        for(String str: strings){
            if(str == null || str.trim().length()== 0)
                return true;
        }
        return false;
    }

    //构造DTO的timeplace字段
    public List<TimePlace> TimePalcesConvert(List<Section> sections){
        List<TimePlace> timePlaces = new ArrayList<>();
        Integer consult = 0;//商 -> 星期几
        Integer remainder = 0;//余数 -> 第几节课
        Integer consultBefore = 0;//商 -> 星期几
        Integer remainderBefore = 0;//余数 -> 第几节课
        int duration = 0;//连续上课的节数  
        boolean isFirst = true;
        int size = sections.size();//sections长度
        String buildingId = "", roomNumber = "";
        if(size == 1){
            String Weekday = getWeekDay(consult);
                String durations = "第"+ remainder + "节";
                TimePlace timePlace = new TimePlace();
                timePlace.setBuildingId(sections.get(0).getBuildingId());
                timePlace.setRoomNumber(sections.get(0).getRoomNumber());
                timePlace.setTime(Weekday + " " + durations);
                consultBefore = consult;
                timePlaces.add(timePlace);        
        }
        else{
            for(Section section: sections){
                Integer periodId = section.getPeriodId();
                consult = periodId / 8;
                remainder = periodId % 8;
                if(consult != 0 && remainder == 0){//对于能整除8的课程，按理说是归属于当天的，因此要减一
                    consult--;
                    remainder = 8;//余数为0以为着是当天的最后一节课，为8
                }
                if(isFirst){
                    consultBefore = consult;
                    remainderBefore = remainder;
                    buildingId = section.getBuildingId();
                    roomNumber = section.getRoomNumber();
                    isFirst = false;
                    continue;
                }
                else if(consultBefore == consult && remainder - remainderBefore == 1){
                    //当在同一天且是连续上课时
                    duration += 1;
                    consultBefore = consult;
                    remainderBefore = remainder;
                    buildingId = section.getBuildingId();
                    roomNumber = section.getRoomNumber();
                    continue;
                }
                String Weekday = getWeekDay(consultBefore);
                String durations = "";
                if(duration == 0){//当只是单节课时
                    durations = "第"+ remainder + "节";
                }
                else{
                    durations = "第"+(remainder-duration) +" - " + remainder + "节";
                }
                TimePlace timePlace = new TimePlace();
                timePlace.setBuildingId(buildingId);
                timePlace.setRoomNumber(roomNumber);
                timePlace.setTime(Weekday + " " + durations);
                consultBefore = consult;
                remainderBefore = remainder;
                buildingId = section.getBuildingId();
                roomNumber = section.getRoomNumber();
                timePlaces.add(timePlace);
                duration = 0;
    
            }
            String Weekday = getWeekDay(consultBefore);
            String durations = "";
            if(duration == 0){//当只是单节课时
                durations = "第"+ remainder + "节";
            }
            else{
                durations = "第"+(remainder-duration) +" - " + remainder + "节";
            }
            TimePlace timePlace = new TimePlace();
            timePlace.setBuildingId(sections.get(size-1).getBuildingId());
            timePlace.setRoomNumber(sections.get(size-1).getRoomNumber());
            timePlace.setTime(Weekday + " " + durations);
            timePlaces.add(timePlace);
        }
        

        return timePlaces;
    }

    public String getWeekDay(Integer consult){
        String weekDay = "";
        switch (consult) {
            case 0:
                weekDay = "星期一";
                break;
            case 1:
                weekDay = "星期二";
                break;
            case 2:
                weekDay = "星期三";
                break;
            case 3:
                weekDay = "星期四";
                break;    
            case 4:
                weekDay = "星期五";
                break;
            case 5:
                weekDay = "星期六";
                break;
            case 6:
                weekDay = "星期天";
                break;
            default:
                break;
        }
        return weekDay;
    }



    //将前端传过来的Sections中的time对象转为数据库表section存储的periodId
    public Integer timeToPeriodId(String time){
        int divisor = 0;
        int remainder = 0;
        //正则判断time格式是否正确 “星期%第%节”
        //确定divisor
        switch (time.charAt(2)) {
            case '二':
                divisor = 1;
                break;
            case '三':
                divisor = 2;
                break;
            case '四':
                divisor = 3;
                break;
            case '五':
                divisor = 4;
                break;
            case '六':
                divisor = 5;
                break;
            case '日':
                divisor = 6;
                break;
            default:
                break;
        }
        //确定remainder
        switch (time.charAt(4)) {
            case '一':
                remainder = 1;
                break;
            case '二':
                remainder = 2;
                break;
            case '三':
                remainder = 3;
                break;
            case '四':
                remainder = 4;
                break;
            case '五':
                remainder = 5;
                break;
            case '六':
                remainder = 6;
                break;
            case '七':
                remainder = 7;
                break;
            case '八':
                remainder = 8;
                break;
            default:
                break;
        }
    
        Integer periodId = 8 * divisor + remainder;

        return periodId;
    }

    
}